/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.worldwizards.saddl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Jeffrey Kesselman
 */
public class Tuple {

    static private Logger logger = Logger.getLogger(Tuple.class.getName());
    String key;
    Object value = null;
    Object myCollection = null;
    
    public Tuple(String inline, Object val) {
        this(inline);
        value = val;
    }
    
    public Tuple(String inline) {
        int equalsPos = inline.indexOf('=');
        if (equalsPos==-1){
            key = inline.trim();
        } else {
            key = inline.substring(0,equalsPos).trim();
            String valstr = inline.substring(equalsPos+1).trim();
            if (valstr.length()>0){
                parseValue(valstr);
            }
        }
    }

    @Override
    public String toString() {
        if (value != null) {
            return (key + ":" + value + "(" + value.getClass().getSimpleName() + ")");
        } else {
            return (key + ":null");
        }
    }

    void addTo(Object coll) {
        if (coll instanceof List) {
            ((List) coll).add(this);
        } else if (coll instanceof Map) {
            ((Map) coll).put(key, this);
        } else { // treat as serialized object
            // first try  bean interface
            Class objClass = coll.getClass();
            String beanName = "set" + Character.toUpperCase(key.charAt(0)) +
                    key.substring(1, key.length());
            try {
                Method m = objClass.getMethod(beanName, value.getClass());
                m.invoke(coll, value);
            } catch (Exception ex) {
                // bean interface failed, try direct access

                Field field = findField(objClass, key);
                if (field == null) {
                    logger.throwing(Tuple.class.getName(),
                            "addTo", new NoSuchFieldException(key));
                    return;
                }
                try {
                    field.set(coll, value);
                } catch (IllegalArgumentException ex1) {
                    Logger.getLogger(Tuple.class.getName()).log(Level.SEVERE, null, ex1);
                } catch (IllegalAccessException ex1) {
                    field.setAccessible(true);
                    try {
                        field.set(coll, value);
                    } catch (IllegalArgumentException ex2) {
                        Logger.getLogger(Tuple.class.getName()).log(Level.SEVERE, null, ex2);
                    } catch (IllegalAccessException ex2) {
                        Logger.getLogger(Tuple.class.getName()).log(Level.SEVERE, null, ex2);
                    }
                }

            }
        }
    }

    void setValue(Object val) {
        value = val;

    }

    public String getKey() {
        return key;
    }

    public Object getValue() {
        return value;
    }

    public void parseValue(String string) {
        string = string.trim();
        if (string.startsWith("\"") && string.endsWith("\"")) { // quoted string
            value = string.substring(1, string.length() - 1);
        } else if (Character.isDigit(string.charAt(0))) { // number of some kind
            Character lastChar = string.charAt(string.length() - 1);
            boolean longval = false;
            if (Character.toUpperCase(lastChar) == 'L') {
                longval = true;
                string = string.substring(0, string.length() - 1);
            }
            if (string.contains(".")) { // is a float
                if (longval) {
                    value = Double.parseDouble(string);
                } else {
                    value = Float.parseFloat(string);
                }
            } else {
                if (longval) {
                    value = Long.parseLong(string);
                } else {
                    value = Integer.parseInt(string);
                }
            }
        } else {
            value = string;
        }
    }

    private Field findField(Class objClass, String key) {
        while (objClass!=null){
            Field[] fields = objClass.getDeclaredFields();
            for (Field f : fields){
                String fieldName = f.getName();
                if (fieldName.equals(key)){
                    return f;
                }
            }
            objClass = objClass.getSuperclass();
        }
        return null;
    }
}
